from nicegui import app, ui

from . import (doc, generic_events_documentation, keyboard_documentation, refreshable_documentation,
               run_javascript_documentation, storage_documentation, timer_documentation)

doc.title('Action & *Events*')

doc.intro(timer_documentation)
doc.intro(keyboard_documentation)


@doc.demo('UI Updates', '''
    NiceGUI tries to automatically synchronize the state of UI elements with the client,
    e.g. when a label text, an input value or style/classes/props of an element have changed.
    In other cases, you can explicitly call `element.update()` or `ui.update(*elements)` to update.
    The demo code shows both methods for a `ui.echart`, where it is difficult to automatically detect changes in the `options` dictionary.
''')
def ui_updates_demo():
    from random import random

    chart = ui.echart({
        'xAxis': {'type': 'value'},
        'yAxis': {'type': 'value'},
        'series': [{'type': 'line', 'data': [[0, 0], [1, 1]]}],
    })

    def add():
        chart.options['series'][0]['data'].append([random(), random()])
        chart.update()

    def clear():
        chart.options['series'][0]['data'].clear()
        ui.update(chart)

    with ui.row():
        ui.button('Add', on_click=add)
        ui.button('Clear', on_click=clear)


doc.intro(refreshable_documentation)


@doc.demo('Async event handlers', '''
    Most elements also support asynchronous event handlers.

    Note: You can also pass a `functools.partial` into the `on_click` property to wrap async functions with parameters.
''')
def async_handlers_demo():
    import asyncio

    async def async_task():
        ui.notify('Asynchronous task started')
        await asyncio.sleep(5)
        ui.notify('Asynchronous task finished')

    ui.button('start async task', on_click=async_task)


doc.intro(generic_events_documentation)


@doc.demo('Running CPU-bound tasks', '''
    NiceGUI provides a `cpu_bound` function for running CPU-bound tasks in a separate process.
    This is useful for long-running computations that would otherwise block the event loop and make the UI unresponsive.
    The function returns a future that can be awaited.
''')
def cpu_bound_demo():
    import time

    from nicegui import run

    def compute_sum(a: float, b: float) -> float:
        time.sleep(1)  # simulate a long-running computation
        return a + b

    async def handle_click():
        result = await run.cpu_bound(compute_sum, 1, 2)
        ui.notify(f'Sum is {result}')

    # ui.button('Compute', on_click=handle_click)
    # END OF DEMO
    async def mock_click():
        import asyncio
        await asyncio.sleep(1)
        ui.notify('Sum is 3')
    ui.button('Compute', on_click=mock_click)


@doc.demo('Running I/O-bound tasks', '''
    NiceGUI provides an `io_bound` function for running I/O-bound tasks in a separate thread.
    This is useful for long-running I/O operations that would otherwise block the event loop and make the UI unresponsive.
    The function returns a future that can be awaited.
''')
def io_bound_demo():
    import requests

    from nicegui import run

    async def handle_click():
        URL = 'https://httpbin.org/delay/1'
        response = await run.io_bound(requests.get, URL, timeout=3)
        ui.notify(f'Downloaded {len(response.content)} bytes')

    ui.button('Download', on_click=handle_click)


doc.intro(run_javascript_documentation)


@doc.demo('Events', '''
    You can register coroutines or functions to be called for the following events:

    - `app.on_startup`: called when NiceGUI is started or restarted
    - `app.on_shutdown`: called when NiceGUI is shut down or restarted
    - `app.on_connect`: called for each client which connects (optional argument: nicegui.Client)
    - `app.on_disconnect`: called for each client which disconnects (optional argument: nicegui.Client)
    - `app.on_exception`: called when an exception occurs (optional argument: exception)

    When NiceGUI is shut down or restarted, all tasks still in execution will be automatically canceled.
''')
def lifecycle_demo():
    from datetime import datetime

    from nicegui import app

    # dt = datetime.now()

    def handle_connection():
        global dt
        dt = datetime.now()
    app.on_connect(handle_connection)

    label = ui.label()
    ui.timer(1, lambda: label.set_text(f'Last new connection: {dt:%H:%M:%S}'))
    # END OF DEMO
    global dt
    dt = datetime.now()


@doc.demo(app.shutdown)
def shutdown_demo():
    from nicegui import app

    # ui.button('shutdown', on_click=app.shutdown)
    #
    # ui.run(reload=False)
    # END OF DEMO
    ui.button('shutdown', on_click=lambda: ui.notify(
        'Nah. We do not actually shutdown the documentation server. Try it in your own app!'))


doc.intro(storage_documentation)
